package com.kcht.itsed.mws;

import com.kcht.itsed.mws.alemodel.*;
import com.kcht.itsed.mws.extendalemodel.HASpec;
import com.kcht.itsed.mws.extendalemodel.PRSpec;
import lombok.extern.slf4j.Slf4j;

import javax.xml.bind.*;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * 模型转换工具
 * 中间件系统中的核心模型均通过XSD定义并生成
 * 通过此工具类进行POJO与XML的相互转换
 * 
 * @author 张文硕
 *
 */
@Slf4j
public class MwsXmlObjFactory<T> implements IMwsXmlObjFactory<T>{

	@SuppressWarnings("serial")
	private static Map<Class<?>,QName> QNAMES = new HashMap<Class<?>,QName>(){{
		put(PRSpec.class, new QName("http://www.shhic.com/ShhicMws-ale-extension","PRSpec", "mws"));
		put(HASpec.class, new QName("http://www.shhic.com/ShhicMws-ale-extension","HASpec", "mws"));
		put(LRSpec.class, new QName("urn:epcglobal:ale:xsd:1","LRSpec", "ale"));
		put(TMSpec.class, new QName("urn:epcglobal:ale:xsd:1","TMSpec", "ale"));
		put(ECSpec.class, new QName("urn:epcglobal:ale:xsd:1","ECSpec", "ale"));
		put(CCSpec.class, new QName("urn:epcglobal:ale:xsd:1","CCSpec", "ale"));
		put(ECReports.class, new QName("urn:epcglobal:ale:xsd:1","ECReports", "ale"));
		put(CCReports.class, new QName("urn:epcglobal:ale:xsd:1","CCReports", "ale"));
	}};
	
//	@SuppressWarnings("serial")
//	private static Map<Class<?>,String> XSDS = new HashMap<Class<?>,String>(){{
//		put(PRSpec.class,"ShhicMws-ale-physicalReader.xsd");
//		put(HASpec.class,"ShhicMws-ale-ha.xsd");
//		put(LRSpec.class,"EPCglobal-ale-1_1_1-alelr.xsd");
//		put(TMSpec.class,"EPCglobal-ale-1_1_1-aletm.xsd");
//		put(ECSpec.class,"EPCglobal-ale-1_1_1-ale.xsd");
//		put(CCSpec.class,"EPCglobal-ale-1_1_1-alecc.xsd");
//		put(ECReports.class,"EPCglobal-ale-1_1_1-ale.xsd");
//		put(CCReports.class,"EPCglobal-ale-1_1_1-alecc.xsd");
//		
//	}};
	
	
	private JAXBContext context;
	private Class<T> modelClass;
	
	private MwsXmlObjFactory() {
		try {
			context = JAXBContext.newInstance(PRSpec.class,HASpec.class,
					LRSpec.class,TMSpec.class,ECSpec.class,CCSpec.class,ECReports.class,CCReports.class);
		} catch (JAXBException e) {
			log.error("",e);
		}
	}
	
	public static <T> IMwsXmlObjFactory<T> create(Class<T> modelClass){
		MwsXmlObjFactory<T> f = new MwsXmlObjFactory<T>();
		f.modelClass = modelClass;
		return f;
	}
	
	@Override
	public String toXml(T model){
		try {
			Marshaller marshaller = context.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			ByteArrayOutputStream outputStream;
			if(model instanceof ECReports || model instanceof CCReports){
				outputStream = new ByteArrayOutputStream(10000);
			}else{
				outputStream = new ByteArrayOutputStream(100000);
			}
			marshaller.marshal(new JAXBElement<T>(QNAMES.get(modelClass),modelClass,null, model),outputStream);
			return new String(outputStream.toByteArray(), "utf-8");
		} catch (JAXBException | UnsupportedEncodingException e) {
			log.error("",e);
			//理论上到不了这里
			throw new RuntimeException(e);
		}
	}
	
	@Override
	public T toModel(String xmlStr){
		try {
			Unmarshaller shaller = context.createUnmarshaller();
//			shaller.setSchema(SchemaFactory.newInstance(
//					XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
//							MwsXmlObjFactory.class.getResource("/"+XSDS.get(modelCls))));
			InputStream stringXmlInputStream = new ByteArrayInputStream(xmlStr.getBytes("utf-8"));
			JAXBElement<T> root = shaller.unmarshal(new StreamSource(stringXmlInputStream), modelClass);
			return root.getValue();
		} catch (JAXBException | UnsupportedEncodingException e) {
			log.error("",e);
			throw new RuntimeException(e);
		}
	}
}
